package com.yugao.fintech.framework.minio.manager;

import cn.hutool.core.util.RandomUtil;
import com.yugao.fintech.framework.assistant.core.UrlUtils;
import com.yugao.fintech.framework.assistant.core.exception.Assert;
import com.yugao.fintech.framework.assistant.core.file.FileUtils;
import com.yugao.fintech.framework.assistant.core.file.MimeTypesUtils;
import com.yugao.fintech.framework.minio.client.CustomMinioClient;
import com.yugao.fintech.framework.minio.utils.MinioUtils;
import com.yugao.fintech.framework.storage.base.config.MinioStorageProperties;
import com.yugao.fintech.framework.storage.base.config.StorageProperties;
import com.yugao.fintech.framework.storage.base.constants.FileStorageEnum;
import com.yugao.fintech.framework.storage.base.manager.BaseStorageManager;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.http.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Consumer;

/**
 * 为minio 设置 nginx 代理: http://docs.minio.org.cn/docs/master/setup-nginx-proxy-with-minio
 */
@Component
public class MinioStorageManager extends BaseStorageManager {
    private static final Logger log = LoggerFactory.getLogger(MinioStorageManager.class);

    @Resource
    private MinioStorageProperties minioStorageProperties;

    @Resource
    private StorageProperties storageProperties;

    @PostConstruct
    public void init() {
        log.info("init {}", this.getClass().getName());
    }

    @Override
    public FileStorageEnum storageType() {
        return FileStorageEnum.MINIO;
    }

    @Override
    public void createClient(String accessKey, String secretKey) throws Exception {
        MinioClient minioClient =
                MinioClient.builder()
                        .endpoint(minioStorageProperties.getEndpoint())
                        .credentials(accessKey, secretKey)
                        .build();
        if (storageProperties.getInitBucket()) {
            // 判断Bucket是否存在
            String bucketName = minioStorageProperties.getBucketName();
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (isExist) {
                log.info("Minio文件系统Bucket: {} 已存在", bucketName);
            } else {
                // 不存在创建一个新的Bucket
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                log.info("Minio已创建Bucket: {}", bucketName);
            }
        }

        CustomMinioClient customMinioClient = new CustomMinioClient(minioClient);
        MinioUtils.init(customMinioClient, minioStorageProperties);
        log.info("Minio文件系统初始化完成");
    }

    @Override
    public String getIntranetUrl(String bucketName, String objectName) {
        String endpoint = minioStorageProperties.getEndpoint();
        String url = endpoint + "/" + bucketName + "/" + objectName;
        return UrlUtils.removeRepeatSlashOfUrl(url);
    }

    @Override
    public String getIntranetUrl(String objectName) {
        String endpoint = minioStorageProperties.getEndpoint();
        String url = endpoint + "/" + minioStorageProperties.getBucketName() + "/" + objectName;
        return UrlUtils.removeRepeatSlashOfUrl(url);
    }

    @Override
    public void uploadText(String text, String objectName) throws Exception {
        String bucketName = minioStorageProperties.getBucketName();
        InputStream inputStream = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));
        MinioUtils.uploadFile(bucketName, inputStream, "text/plain", objectName);
    }

    @Override
    public void uploadFile(InputStream inputStream, String contentType, String objectName) throws Exception {
        String bucketName = minioStorageProperties.getBucketName();
        MinioUtils.uploadFile(bucketName, inputStream, contentType, objectName);
    }

    @Override
    public void uploadFile(String bucketName, InputStream inputStream, String contentType, String objectName) throws Exception {
        MinioUtils.uploadFile(bucketName, inputStream, contentType, objectName);
    }

    @Override
    public void uploadDir(String dirPath) {
        List<String> allFileList = FileUtils.getAllFile(dirPath, false, null);
        dirPath = dirPath.replace("\\", "/");

        if (!dirPath.endsWith("/")) {
            dirPath = dirPath + "/";
        }

        for (String filePath : allFileList) {
            String path = filePath.replace("\\", "/").replace(dirPath, "");

            // 针对win路径进行处理
            if (path.contains(":")) {
                path = path.substring(path.lastIndexOf(":") + 1);
            }

            String objectName = path;
            try (InputStream inputStream = Files.newInputStream(Paths.get(filePath))) {
                uploadFile(inputStream, MimeTypesUtils.getInstance().getMimetype(FileUtils.getName(filePath)), objectName);
            } catch (Exception e) {
                log.error("error: ", e);
            }
        }
    }

    @Override
    public String getObjectUrl(String objectName) {
        String bucketName = minioStorageProperties.getBucketName();
        String url = MinioUtils.getFileUrl(bucketName, objectName, Method.GET);
        Assert.notEmpty(url, "获取url失败");
//        if (UrlTypesEnum.INTERNAL.equals(urlTypes)) {
//            String internal = storageProperties.getUrl().getInternal();
//            return internal + url.replace(storageProperties.getMinio().getEndpoint(), "");
//        } else {
//            String external = storageProperties.getUrl().getExternal();
//            return external + url.replace(storageProperties.getMinio().getEndpoint(), "");
//        }
        return url;
    }

    @Override
    public InputStream getFile(String objectName) {
        String bucketName = minioStorageProperties.getBucketName();
        return MinioUtils.getFile(bucketName, objectName);
    }

    @Override
    public List<String> listFilePath(String pathPrefix) {
        String bucketName = minioStorageProperties.getBucketName();
        return MinioUtils.listFilePath(bucketName, pathPrefix, null);
    }

    @Override
    public List<String> listFilePath(String pathPrefix, Consumer<String> filePathCallback) {
        String bucketName = minioStorageProperties.getBucketName();
        return MinioUtils.listFilePath(bucketName, pathPrefix, filePathCallback);
    }

    @Override
    public Boolean createBucket(Boolean randomSuffix) {
        String bucketName = minioStorageProperties.getBucketName();
        try {
            if (randomSuffix != null && randomSuffix) {
                MinioUtils.createBucket(bucketName + "-" + RandomUtil.randomString(8));
            } else {
                MinioUtils.createBucket(bucketName);
            }
        } catch (Exception e) {
            log.error("createBucket::bucketName = [{}] message = {}", bucketName, e.getMessage());
            return false;
        }
        return true;
    }

    @Override
    public Boolean createBucket(String bucketName) {
        try {
            MinioUtils.createBucket(bucketName);
        } catch (Exception e) {
            log.error("createBucket::bucketName = [{}] message = {}", bucketName, e.getMessage());
            return false;
        }
        return true;
    }

    @Override
    public Boolean doesBucketExist(String bucketName) {
        return MinioUtils.bucketExists(bucketName);
    }

    @Override
    public void deleteObjects(List<String> objectNameList) throws Exception {
        String bucketName = minioStorageProperties.getBucketName();
        MinioUtils.deleteObjects(bucketName, objectNameList);
    }

    @Override
    public void deleteObjects(String bucketName, List<String> objectNameList) throws Exception {
        MinioUtils.deleteObjects(bucketName, objectNameList);
    }

    @Override
    public void deleteObject(String objectName) throws Exception {
        String bucketName = minioStorageProperties.getBucketName();
        MinioUtils.deleteObject(bucketName, objectName);
    }

    @Override
    public void deleteObject(String bucketName, String objectName) throws Exception {
        MinioUtils.deleteObject(bucketName, objectName);
    }

    @Override
    public boolean checkFileIsExist(String objectName) {
        String bucketName = minioStorageProperties.getBucketName();
        return MinioUtils.checkFileIsExist(bucketName, objectName);
    }

    @Override
    public boolean checkFolderIsExist(String folderName) {
        String bucketName = minioStorageProperties.getBucketName();
        return MinioUtils.checkFolderIsExist(bucketName, folderName);
    }
}
